package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
	"text/template"
	"unicode"
	"unicode/utf8"

	"github.com/constabulary/gb/cmd"
)

func init() {
	registerCommand(helpProject)
}

var helpProject = &cmd.Command{
	Name:  "project",
	Short: "gb project layout",
	Long: `A gb project is defined as any directory that contains a src/ subdirectory.
gb automatically detects the root of the project by looking at the current
working directory and walking backwards until it finds a directory that
contains a src/ subdirectory.

In the event you wish to override this auto detection mechanism, the -R flag
can be used to supply a project root.

See http://getgb.io/docs/project for details`,
}

var helpTemplate = `{{if .Runnable}}usage: gb {{.UsageLine}}

{{end}}{{.Long | trim}}
`

// help implements the 'help' command.
func help(args []string) {
	if len(args) == 0 {
		printUsage(os.Stdout)
		// not exit 2: succeeded at 'gb help'.
		return
	}
	if len(args) != 1 {
		fmt.Fprintf(os.Stderr, "usage: gb help command\n\nToo many arguments given.\n")
		exit(2) // failed at 'gb help'
	}

	arg := args[0]

	// 'gb help documentation' generates alldocs.go.
	if arg == "documentation" {
		var buf bytes.Buffer
		printUsage(&buf)
		usage := &cmd.Command{Long: buf.String()}
		f, _ := os.Create("alldocs.go")
		tmpl(f, documentationTemplate, append([]*cmd.Command{usage}, sortedCommands()...))
		f.Close()
		return
	}

	for _, cmd := range commands {
		if cmd.Name == arg {
			tmpl(os.Stdout, helpTemplate, cmd)
			// not exit 2: succeeded at 'gb help cmd'.
			return
		}
	}

	fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'gb help'.\n", arg)
	exit(2) // failed at 'gb help cmd'
}

var usageTemplate = `gb, a project based build tool for the Go programming language.

Usage:

        gb command [arguments]

The commands are:
{{range .}}{{if .Runnable}}
        {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}

Use "gb help [command]" for more information about a command.

Additional help topics:
{{range .}}{{if not .Runnable}}
        {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}

Use "gb help [topic]" for more information about that topic.
`

var documentationTemplate = `// DO NOT EDIT THIS FILE.
//go:generate gb help documentation

/*
{{range .}}{{if .Short}}{{.Short | capitalize}}

{{end}}{{if .Runnable}}Usage:

        gb {{.UsageLine}}

{{end}}{{.Long | trim}}


{{end}}*/
package main
`

// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
	t := template.New("top")
	t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
	template.Must(t.Parse(text))
	if err := t.Execute(w, data); err != nil {
		panic(err)
	}
}

func capitalize(s string) string {
	if s == "" {
		return s
	}
	r, n := utf8.DecodeRuneInString(s)
	return string(unicode.ToTitle(r)) + s[n:]
}

func printUsage(w io.Writer) {
	bw := bufio.NewWriter(w)
	tmpl(bw, usageTemplate, sortedCommands())
	bw.Flush()
}

func sortedCommands() []*cmd.Command {
	// TODO(dfc) drop this and make main.commands a []*cmd.Command
	var sortedKeys []string
	for k := range commands {
		sortedKeys = append(sortedKeys, k)
	}

	sort.Strings(sortedKeys)
	var cmds []*cmd.Command
	for _, c := range sortedKeys {

		// skip hidden commands
		if commands[c].Hidden() {
			continue
		}

		cmds = append(cmds, commands[c])
	}
	return cmds
}

func usage() {
	printUsage(os.Stderr)
	exit(2)
}
